package implementation;

import static org.junit.Assert.*;

import java.util.Set;

import org.junit.Test;

public class BoardTest {

	/*
	 * 
	 * AddTests voor wall, robot en battery
	 * 
	 * 
	 */

	// voeg wall toe aan een leeg vakje
	@Test
	public final void addWall_emptySpace(){
		Board board = new Board(1000, 1000);
		Wall wall = new Wall();
		board.addWall(5, 5, wall);
		long[] key = {5,5};
		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getWalls().contains(wall));
	}

	// voeg wall toe aan een vakje waar al een wall op staat. (mag niet lukken)
	@Test
	public final void addWall_wallOnSpace(){
		Board board = new Board(1000, 1000);
		long[] key = {5,5};

		Wall wall = new Wall();
		board.addWall(5, 5, wall);
		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getWalls().contains(wall)); //kijk of wall bestaat voor en na toevoegen wall2.

		Wall wall2 = new Wall();
		board.addWall(5, 5, wall2);
		assertTrue(board.getLocation(key).getWalls().contains(wall));
		assertFalse(board.getLocation(key).getWalls().contains(wall2));
	}


	// voeg wall toe aan een vakje waar een robot op staat. (mag niet lukken)
	@Test
	public final void addWall_robotOnSpace(){
		Board board = new Board(1000, 1000);
		long[] key = {5,5};

		Robot robot = new Robot(1, 20000.0);
		board.addRobot(5, 5, robot);
		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getRobots().contains(robot)); //kijk of robot bestaat voor en na toevoegen wall.

		Wall wall = new Wall();
		board.addWall(5, 5, wall);
		assertFalse(board.getLocation(key).getWalls().contains(wall));
		assertTrue(board.getLocation(key).getRobots().contains(robot));
	}

	// voeg wall toe aan een vakje waar een battery op staat. (mag niet lukken)
	@Test
	public final void addWall_batteryOnSpace(){
		Board board = new Board(1000, 1000);
		long[] key = {5,5};

		Battery battery = new Battery(2000.0, 500);
		board.addBattery(5, 5, battery);
		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getBatteries().contains(battery)); //kijk of battery bestaat voor en na toevoegen wall.

		Wall wall = new Wall();
		board.addWall(5, 5, wall);
		assertFalse(board.getLocation(key).getWalls().contains(wall));
		assertTrue(board.getLocation(key).getBatteries().contains(battery));
	}

	// voeg niet bestaande wall toe. (mag niet lukken)
	@Test(expected = NullPointerException.class)
	public final void addWall_null() throws Exception{
		Board board = new Board(1000, 1000);
		long[] key = {5,5};

		Battery battery = null;
		board.addBattery(5, 5, battery);
		assertNull(board.getLocation(key));
	}

	// voeg robot toe aan een leeg vakje
	@Test
	public final void addRobot_emptySpace(){
		Board board = new Board(1000, 1000);
		Robot robot = new Robot(1, 20000.0);
		board.addRobot(5, 5, robot);
		long[] key = {5,5};
		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getRobots().contains(robot));
	}

	// voeg robot toe aan een vakje waar een battery op ligt.
	@Test
	public final void addRobot_batteryOnSpace(){
		Board board = new Board(1000, 1000);
		long[] key = {5,5};

		Battery battery = new Battery(2000.0, 500);
		board.addBattery(5, 5, battery);
		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getBatteries().contains(battery)); //kijk of battery bestaat voor en na toevoegen robot.

		Robot robot = new Robot(1, 20000.0);
		board.addRobot(5, 5, robot);
		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertTrue(board.getLocation(key).getBatteries().contains(battery));
	}

	// voeg robot toe aan een vakje waar een robot op ligt. (mag niet lukken)
	@Test
	public final void addRobot_robotOnSpace(){
		Board board = new Board(1000, 1000);
		long[] key = {5,5};

		Robot robot = new Robot(1, 20000.0);
		board.addRobot(5, 5, robot);
		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getRobots().contains(robot)); //kijk of robot bestaat voor en na toevoegen robot2.

		Robot robot2 = new Robot(1, 20000.0);
		board.addRobot(5, 5, robot2);
		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertFalse(board.getLocation(key).getRobots().contains(robot2));
	}

	// voeg robot toe aan een vakje waar een wall op staat. (mag niet lukken)
	@Test
	public final void addRobot_wallOnSpace(){
		Board board = new Board(1000, 1000);
		long[] key = {5,5};

		Wall wall = new Wall();
		board.addWall(5, 5, wall);
		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getWalls().contains(wall)); //kijk of wall bestaat voor en na toevoegen robot.

		Robot robot = new Robot(1, 20000.0);
		board.addRobot(5, 5, robot);
		assertTrue(board.getLocation(key).getWalls().contains(wall));
		assertFalse(board.getLocation(key).getRobots().contains(robot));
	}

	// voeg niet bestaande wall toe. (mag niet lukken)
	@Test(expected = NullPointerException.class)
	public final void addRobot_null() throws Exception{
		Board board = new Board(1000, 1000);
		long[] key = {5,5};

		Robot robot = null;
		board.addRobot(5, 5, robot);
		assertNull(board.getLocation(key));
	}

	// voeg battery toe aan een leeg vakje
	@Test
	public final void addBattery_emptySpace(){
		Board board = new Board(1000, 1000);
		Battery battery = new Battery(2000.0, 500);
		board.addBattery(5, 5, battery);
		long[] key = {5,5};
		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getBatteries().contains(battery));
	}

	// voeg battery toe aan een vakje waar een robot op ligt.
	@Test
	public final void addBattery_robotOnSpace(){
		Board board = new Board(1000, 1000);
		long[] key = {5,5};

		Robot robot = new Robot(1, 20000.0);
		board.addRobot(5, 5, robot);
		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getRobots().contains(robot)); //kijk of robot bestaat voor en na toevoegen battery.

		Battery battery = new Battery(2000.0, 500);
		board.addBattery(5, 5, battery);
		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertTrue(board.getLocation(key).getBatteries().contains(battery));
	}

	// voeg battery toe aan een vakje waar al een battery op ligt.
	@Test
	public final void addBattery_batteryOnSpace(){
		Board board = new Board(1000, 1000);
		long[] key = {5,5};

		Battery battery = new Battery(2000.0, 500);
		board.addBattery(5, 5, battery);
		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getBatteries().contains(battery)); //kijk of battery bestaat voor en na toevoegen battery2.

		Battery battery2 = new Battery(2000.0, 500);
		board.addBattery(5, 5, battery2);
		assertTrue(board.getLocation(key).getBatteries().contains(battery));
		assertTrue(board.getLocation(key).getBatteries().contains(battery2));
	}

	// voeg battery toe aan een vakje waar al een wall op staat. (mag niet lukken)
	@Test
	public final void addBattery_wallOnSpace(){
		Board board = new Board(1000, 1000);
		long[] key = {5,5};

		Wall wall = new Wall();
		board.addWall(5, 5, wall);
		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getWalls().contains(wall)); //kijk of wall bestaat voor en na toevoegen battery.

		Battery battery = new Battery(2000.0, 500);
		board.addBattery(5, 5, battery);
		assertTrue(board.getLocation(key).getWalls().contains(wall));
		assertFalse(board.getLocation(key).getBatteries().contains(battery));
	}

	// voeg niet bestaande wall toe. (mag niet lukken)
	@Test(expected = NullPointerException.class)
	public final void addBattery_null() throws Exception{
		Board board = new Board(1000, 1000);
		long[] key = {5,5};

		Battery battery = null;
		board.addBattery(5, 5, battery);
		assertNull(board.getLocation(key));
	}
	
	// Voeg 3 items (battery, repairKit, surpriseBox toe aan 1 vakje)
	@Test
	public final void addItem_Battery_RepairKit_SurpriseBox(){
		Board board = new Board(1000, 1000);

		Battery battery = new Battery(2000.0, 500);
		board.addItem(5, 5, battery);
		RepairKit kit = new RepairKit(2000.0, 500);
		board.addItem(5, 5, kit);
		SurpriseBox box = new SurpriseBox(500);
		board.addItem(5, 5, box);
		assertTrue(board.getBatteries().contains(battery));
		assertTrue(board.getRepairKits().contains(kit));
		assertTrue(board.getSurpriseBoxes().contains(box));
	}
	
	
	/*
	 * 
	 * RemoveTests voor wall robot en battery
	 * 
	 * 
	 */

	// verwijder wall van een leeg vakje
	@Test
	public final void removeWall_emptySpace(){
		Board board = new Board(1000, 1000);
		Wall wall = new Wall();
		board.addWall(6, 6, wall);
		long[] key = {6,6};
		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getWalls().contains(wall));
		board.getLocation(key).removeWall(wall);
		assertNull(board.getLocation(key));
	}

	// verwijder robot van een leeg vakje
	@Test
	public final void removeRobot_emptySpace(){
		Board board = new Board(1000, 1000);
		Robot robot = new Robot(1, 20000.0);
		board.addRobot(6, 6, robot);
		long[] key = {6,6};
		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getRobots().contains(robot));
		board.getLocation(key).removeRobot(robot);
		assertNull(board.getLocation(key));
	}

	// verwijder robot van een vakje waar ook een battery op ligt.
	@Test
	public final void removeRobot_batteryOnSpace(){
		Board board = new Board(1000, 1000);
		long[] key = {6,6};

		Robot robot = new Robot(1, 20000.0);
		board.addRobot(6, 6, robot);
		Battery battery = new Battery(2000.0, 500);
		board.addBattery(6, 6, battery);

		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertTrue(board.getLocation(key).getBatteries().contains(battery));

		board.getLocation(key).removeRobot(robot);

		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getBatteries().contains(battery));
		assertFalse(board.getLocation(key).getRobots().contains(robot));
	}

	// verwijder battery van een leeg vakje
	@Test
	public final void removeBattery_emptySpace(){
		Board board = new Board(1000, 1000);
		Battery battery = new Battery(2000.0, 500);
		board.addBattery(6, 6, battery);
		long[] key = {6,6};
		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getBatteries().contains(battery));
		board.getLocation(key).removeItem(battery);
		assertNull(board.getLocation(key));
	}

	// verwijder battery van een vakje waar ook een andere battery op ligt
	@Test
	public final void removeBattery_batteryOnSpace(){
		Board board = new Board(1000, 1000);
		long[] key = {6,6};

		Battery battery = new Battery(2000.0, 500);
		board.addBattery(6, 6, battery);
		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getBatteries().contains(battery));

		Battery battery2 = new Battery(2000.0, 500);
		board.addBattery(6, 6, battery2);
		assertTrue(board.getLocation(key).getBatteries().contains(battery2));

		board.getLocation(key).removeItem(battery);

		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getBatteries().contains(battery2));
		assertFalse(board.getLocation(key).getBatteries().contains(battery));
	}

	// verwijder battery van een vakje waar ook een robot op staat.
	@Test
	public final void removeBattery_robotOnSpace(){
		Board board = new Board(1000, 1000);
		long[] key = {6,6};

		Robot robot = new Robot(1, 20000.0);
		board.addRobot(6, 6, robot);
		Battery battery = new Battery(2000.0, 500);
		board.addBattery(6, 6, battery);

		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertTrue(board.getLocation(key).getBatteries().contains(battery));

		board.getLocation(key).removeItem(battery);

		assertNotNull(board.getLocation(key));
		assertFalse(board.getLocation(key).getBatteries().contains(battery));
		assertTrue(board.getLocation(key).getRobots().contains(robot));
	}
	
	/*
	 * 
	 * GetterTests voor wall robot en battery.
	 * 
	 * 
	 */
	
	// getWalls met 3 walls
	@Test
	public final void getWalls_3Walls(){
		Board board = new Board(10, 10);
		
		Wall wall = new Wall();
		board.addWall(5, 5, wall);
		Wall wall2 = new Wall();
		board.addWall(6, 6, wall2);
		Wall wall3 = new Wall();
		board.addWall(7, 7, wall3);

		Set<Wall> walls = board.getWalls();

		assertEquals(walls.size(), 3);
		assertTrue(walls.contains(wall));
		assertTrue(walls.contains(wall2));
		assertTrue(walls.contains(wall3));
	}
	
	// getRobots met 3 robots
	@Test
	public final void getRobots_3Robots(){
		Board board = new Board(10, 10);
		
		Robot robot = new Robot(1, 20000.0);
		board.addRobot(5, 5, robot);
		Robot robot2 = new Robot(1, 20000.0);
		board.addRobot(6, 6, robot2);
		Robot robot3 = new Robot(1, 20000.0);
		board.addRobot(7, 7, robot3);

		Set<Robot> robots = board.getRobots();

		assertEquals(robots.size(), 3);
		assertTrue(robots.contains(robot));
		assertTrue(robots.contains(robot2));
		assertTrue(robots.contains(robot3));
	}
	
	// getBatteries met 3 batteries
		@Test
		public final void getBatteries_3Batteries(){
			Board board = new Board(10, 10);
			
			Battery battery = new Battery(2000.0, 500);
			board.addBattery(5, 5, battery);
			Battery battery2 = new Battery(2000.0, 500);
			board.addBattery(6, 6, battery2);
			Battery battery3 = new Battery(2000.0, 500);
			board.addBattery(7, 7, battery3);

			Set<Battery> batteries = board.getBatteries();

			assertEquals(batteries.size(), 3);
			assertTrue(batteries.contains(battery));
			assertTrue(batteries.contains(battery2));
			assertTrue(batteries.contains(battery3));
		}



	/*
	 * 
	 * MergeTests voor board
	 * 
	 * 
	 */

	// merge 2 boards zonder meer dan 1 robot, wall of battery per locatie en zonder locaties op board2 die niet kunnen bestaan op board1
	@Test
	public final void merge_simple(){
		Board board1 = new Board(10, 10);
		Board board2 = new Board(10, 10);
		long[] key1 = {1,2};
		long[] key2 = {3,4};
		long[] key3 = {5,6};
		long[] key4 = {7,8};
		long[] key5 = {9,9};
		long[] key6 = {0,0};

		Robot robot1 = new Robot(1, 20000.0);
		board1.addRobot(1, 2, robot1);
		Robot robot2 = new Robot(1, 20000.0);
		board2.addRobot(3, 4, robot2);

		Battery battery1 = new Battery(2000.0, 500);
		board1.addBattery(5, 6, battery1);
		Battery battery2 = new Battery(2000.0, 500);
		board2.addBattery(7, 8, battery2);

		Wall wall1 = new Wall();
		board1.addWall(9, 9, wall1);
		Wall wall2 = new Wall();
		board2.addWall(0, 0, wall2);

		board1.merge(board2);

		assertTrue(board2.isTerminated());
		assertNotNull(board1.getLocation(key1));
		assertNotNull(board1.getLocation(key2));
		assertNotNull(board1.getLocation(key3));
		assertNotNull(board1.getLocation(key4));
		assertNotNull(board1.getLocation(key5));
		assertNotNull(board1.getLocation(key6));
		
		assertNull(board2.getLocation(key2));
		assertNull(board2.getLocation(key4));
		assertNull(board2.getLocation(key6));

		assertTrue(board1.getLocation(key1).getRobots().contains(robot1));
		assertTrue(board1.getLocation(key2).getRobots().contains(robot2));
		assertTrue(board1.getLocation(key3).getBatteries().contains(battery1));
		assertTrue(board1.getLocation(key4).getBatteries().contains(battery2));
		assertTrue(board1.getLocation(key5).getWalls().contains(wall1));
		assertTrue(board1.getLocation(key6).getWalls().contains(wall2));
	}

	// merge 2 boards met locaties op board2 die niet kunnen bestaan op board1
	@Test
	public final void merge_boardSize(){
		Board board1 = new Board(10, 10);
		Board board2 = new Board(20, 20);
		long[] key1 = {1,1};
		long[] key2 = {11,11};
		long[] key3 = {0,0};
		long[] key4 = {10,10};
		long[] key5 = {9,9};
		long[] key6 = {2,2};

		Robot robot1 = new Robot(1, 20000.0);
		board2.addRobot(1, 1, robot1);
		Robot robot2 = new Robot(1, 20000.0);
		board2.addRobot(11, 11, robot2);

		Battery battery1 = new Battery(2000.0, 500);
		board2.addBattery(0, 0, battery1);
		Battery battery2 = new Battery(2000.0, 500);
		board2.addBattery(10, 10, battery2);

		Wall wall1 = new Wall();
		board2.addWall(9, 9, wall1);
		Wall wall2 = new Wall();
		board2.addWall(2, 2, wall2);

		board1.merge(board2);

		assertTrue(board2.isTerminated());
		assertNotNull(board1.getLocation(key1));
		assertNull(board1.getLocation(key2));
		assertNotNull(board1.getLocation(key3));
		assertNull(board1.getLocation(key4));
		assertNotNull(board1.getLocation(key5));
		assertNotNull(board1.getLocation(key6));

		assertNull(board2.getLocation(key1));
		assertNull(board2.getLocation(key2));
		assertNull(board2.getLocation(key3));
		assertNull(board2.getLocation(key4));
		assertNull(board2.getLocation(key5));
		assertNull(board2.getLocation(key6));

		assertTrue(board1.getLocation(key1).getRobots().contains(robot1));
		assertTrue(robot2.isTerminated());
		assertTrue(board1.getLocation(key3).getBatteries().contains(battery1));
		assertTrue(battery2.isTerminated());
		assertTrue(board1.getLocation(key5).getWalls().contains(wall1));
		assertTrue(board1.getLocation(key6).getWalls().contains(wall2));
	}

	// merge 2 boards even grote boards met locaties op board2 waarvoor reeds een locatie bestaat op board1
	@Test
	public final void merge_sameLocationsSucces(){
		Board board1 = new Board(10, 10);
		Board board2 = new Board(10, 10);
		long[] key1 = {0,0};
		long[] key2 = {1,1};
		long[] key3 = {2,2};
		
		// battery toevoegen waar robot staat
		Robot robot1 = new Robot(1, 20000.0);
		board1.addRobot(0, 0, robot1);
		Battery battery1 = new Battery(2000.0, 500);
		board2.addBattery(0, 0, battery1);
		
		// robot toevoegen waar battery staat
		Battery battery2 = new Battery(2000.0, 500);
		board1.addBattery(1, 1, battery2);
		Robot robot2 = new Robot(1, 20000.0);
		board2.addRobot(1, 1, robot2);
		
		// battery toevoegen waar een andere battery staat
		Battery battery3 = new Battery(2000.0, 500);
		board1.addBattery(2, 2, battery3);
		Battery battery4 = new Battery(2000.0, 500);
		board2.addBattery(2, 2, battery4);

		board1.merge(board2);

		assertTrue(board2.isTerminated());
		assertNotNull(board1.getLocation(key1));
		assertNotNull(board1.getLocation(key2));
		assertNotNull(board1.getLocation(key3));

		assertNull(board2.getLocation(key1));
		assertNull(board2.getLocation(key2));
		assertNull(board2.getLocation(key3));
		
		assertTrue(board1.getLocation(key1).getRobots().contains(robot1));
		assertTrue(board1.getLocation(key1).getBatteries().contains(battery1));
		
		assertTrue(board1.getLocation(key2).getRobots().contains(robot2));
		assertTrue(board1.getLocation(key2).getBatteries().contains(battery2));
		
		assertTrue(board1.getLocation(key3).getBatteries().contains(battery3));
		assertTrue(board1.getLocation(key3).getBatteries().contains(battery4));
	}


}
